In [ ]:
import numpy as np

In [ ]:
%run magic.ipynb

Feedforward Network

一樣有輸入 x, 輸出 y。 但是中間預測、計算的樣子有點不同。

模型是這樣的

一樣考慮輸入是四維向量,輸出有 3 個類別。

我們的輸入 $x=\begin{pmatrix} x_0 \\ x_1 \\ x_2 \\ x_3 \end{pmatrix} $ 是一個向量,我們看成 column vector 好了

第 0 層

而 Weight: $ W^{(0)} = \begin{pmatrix} W^{(0)}_0 \\ W^{(0)}_1 \\ W^{(0)}_2 \\ W^{(0)}_3 \\ W^{(0)}_4 \\ W^{(0)}_5 \end{pmatrix} = \begin{pmatrix} W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3}\\ W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3}\\ W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3}\\ W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3}\\ W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3}\\ W^{(0)}_{0,0} & W^{(0)}_{0,1} & W^{(0)}_{0,2} & W^{(0)}_{0,3} \end{pmatrix} $

Bias: $b^{(0)}=\begin{pmatrix} b^{(0)}_0 \\ b^{(0)}_1 \\ b^{(0)}_2 \\ b^{(0)}_3 \\ b^{(0)}_4 \\ b^{(0)}_5 \end{pmatrix} $

我們先計算"線性輸出" $ c^{(0)} = \begin{pmatrix} c^{(0)}_0 \\ c^{(0)}_1 \\ c^{(0)}_2 \\ c^{(0)}_3 \\ c^{(0)}_4 \\ c^{(0)}_5 \end{pmatrix} = W^{(0)}x+b^{(0)} = \begin{pmatrix} W^{(0)}_0 x + b^{(0)}_0 \\ W^{(0)}_1 x + b^{(0)}_1 \\ W^{(0)}_2 x + b^{(0)}_2 \\ W^{(0)}_3 x + b^{(0)}_3 \\ W^{(0)}_4 x + b^{(0)}_4 \\ W^{(0)}_5 x + b^{(0)}_5 \end{pmatrix} $,

然後再將結果逐項對一個非線性的函數 $f$ 最後得到一個向量。

$d^{(0)} = \begin{pmatrix} d^{(0)}_0 \\ d^{(0)}_1 \\ d^{(0)}_2 \\ d^{(0)}_3 \\ d^{(0)}_4 \\ d^{(0)}_5 \end{pmatrix} = f({W x + b}) = \begin{pmatrix} f(c^{(0)}_0) \\ f(c^{(0)}_1) \\ f(c^{(0)}_2) \\ f(c^{(0)}_3) \\ f(c^{(0)}_4) \\ f(c^{(0)}_5) \end{pmatrix} $

這裡的 $f$ 常常會用 sigmoid , tanh,或者 ReLU ( https://en.wikipedia.org/wiki/Activation_function )。

第 1 層

這裡接到輸出,其實和 softmax regression 一樣。

只是輸入變成 $d^{(0)}, Weight 和 Bias 現在叫做 W^{(1)} 和 b^{(1)}

因為維度改變,現在 W^{(1)} 是 3x6 的矩陣。 後面接到的輸出都一樣。

所以線性輸出

$ c^{(1)} = W^{(1)} d^{(0)} + b^{(1)} $

$ d^{(1)} = e^{c^{(1)}} $

當輸入為 x, 最後的 softmax 預測類別是 i 的機率為

$q_i = Predict_{W^{(0)}, W^{(1)}, b^{(0)}, b^{(1)}}(Y=i|x) = \frac {d^{(1)}_i} {\sum_j d^{(1)}_j}$

合起來看,就是 $q = \frac {d^{(1)}} {\sum_j d^{(1)}_j}$

問題

我們簡化一下算式,如果 $W^{(0)}, W^{(1)}, b^{(0)}, b^{(1)}$ 設定為 $A, b, C, d$ (C, d 與前面無關),請簡化成為一個算式。 可以利用 softmax function 的符號

$\sigma (\mathbf {z} )_{j}={\frac {e^{z_{j}}}{\sum _k e^{z_{k}}}}$


In [ ]:
# 參考答案
%run solutions/ff_oneline.py

任務:計算最後的猜測機率 $q$

設定:輸入 4 維, 輸出 3 維, 隱藏層 6 維

  • 設定一些權重 $A,b,C,d$ (隨意自行填入,或者用 np.random.randint(-2,3, size=...))
  • 設定輸入 $x$ (隨意自行填入,或者用 np.random.randint(-2,3, size=...))
  • 自行定義 relu, sigmoid 函數 (Hint: np.maximum)
  • 算出隱藏層 $z$
  • 自行定義 softmax
  • 算出最後的 q

In [ ]:
# 請在這裡計算
np.random.seed(1234)

In [ ]:
# 參考答案,設定權重
%run -i solutions/ff_init_variables.py
display(A)
display(b)
display(C)
display(d)
display(x)

In [ ]:
# 參考答案 定義 relu, sigmoid 及計算 z
%run -i solutions/ff_compute_z.py
display(z_relu)
display(z_sigmoid)

In [ ]:
# 參考答案 定義 softmax 及計算 q
%run -i solutions/ff_compute_q.py
display(q_relu)
display(q_sigmoid)

練習

設計一個網路:

  • 輸入是二進位 0 ~ 15
  • 輸出依照對於 3 的餘數分成三類

In [ ]:
# Hint 下面產生數字 i 的 2 進位向量
i = 13
x = Vector(i%2, (i>>1)%2, (i>>2)%2, (i>>3)%2)
x

In [ ]:
# 請在這裡計算

In [ ]:
# 參考解答
%run -i solutions/ff_mod3.py

練習

設計一個網路來判斷井字棋是否有連成直線(只需要判斷其中一方即可):

  • 輸入是 9 維向量,0 代表空格,1 代表有下子
  • 輸出是二維(softmax)或一維(sigmoid)皆可,用來代表 True, False

有連線的例子

_X_
X__
XXX

XXX
XX_
_XX

__X
_XX
X__

沒連線的例子

XX_
X__
_XX

_X_
XX_
X_X

__X
_XX
_X_

In [ ]:
# 請在這裡計算

In [ ]:
#參考答案
%run -i solutions/ff_tic_tac_toe.py

In [ ]:
# 測試你的答案
def my_result(x):
    # return 0 means no, 1 means yes
    return (C@relu(A@x+b)+d).argmax()
    # or sigmoid based
    # return (C@relu(A@x+b)+d) > 0

def truth(x):
    x = x.reshape(3,3)
    return (x.all(axis=0).any() or
            x.all(axis=1).any() or
            x.diagonal().all() or
            x[::-1].diagonal().all())

for i in range(512):
    x = np.array([[(i>>j)&1] for j in range(9)])
    assert my_result(x) == truth(x)
print("test passed")

In [ ]: